package com.aoyebobi;

import com.aoyebobi.pojo.EClass;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @Description
 * @Author aoyebobi
 * @Date 2024-08-28
 */
public class PojoToResultMapUtils {

   /**
    * 简单类型pojo转换为resultMap
    * 默认采用驼峰命名
    * @param pojoClass   pojo类
    * @return resultMap
    * @param <T>
    */
   public static <T> String pojoToResultMap(Class<T> pojoClass){
       //最终结果
       StringBuilder resultMap = new StringBuilder();
       //反射获取类名 和 类的包名
       String classPath = pojoClass.getName();
       String className = classPath.substring(classPath.lastIndexOf(".") + 1);
       resultMap.append("<resultMap id=\"").append(className).append("Map\" type=\"").append(classPath).append("\">\n");
       //处理基本数据类型
       String pojoResultMap = pojoCore(pojoClass);
       resultMap.append(pojoResultMap);

       iteration(pojoClass, resultMap);

       resultMap.append("</resultMap>");
       return resultMap.toString();
   }

    /**
     * pojo基本数据类型处理逻辑
     * @param pojoClass
     * @return
     * @param <T>
     */
   private static <T> String pojoCore(Class<T> pojoClass){
       StringBuilder stringBuilder = new StringBuilder();
       //反射获取pojo类的属性
       Field[] fields = pojoClass.getDeclaredFields();
       for (Field field : fields) {
           //获取属性名称
           String property = field.getName();
           //判断是否是基本类型
           if (isCommonType(field)) {
               //如果是基本类型，则直接添加到resultMap中
               String column = camelCaseCast(property);
               stringBuilder.append("<result property=\"").append(property).append("\" column=\"").append(column).append("\"/>\n");
           }
       }
       return stringBuilder.toString();
   }
   
    /**
     * 主要嵌套逻辑
     * @param pojoClass
     * @param resultMap
     * @param <T>
     */
   private static <T> void iteration(Class<T> pojoClass, StringBuilder resultMap){
       //判断是否有其他类型属性
       List<Field> childPojo = getChildPojo(pojoClass);
       if (!childPojo.isEmpty()) {
           for (Field field : childPojo) {
               resultMap.append(getAssociation(field));
           }
       }
       List<Field> childCollection = getChildCollection(pojoClass);
       if (!childCollection.isEmpty()) {
           for (Field field : childCollection) {
               resultMap.append(getCollection(field));
           }
       }
   }


    /**
     * 处理对象类型属性
     * @param field
     * @return
     */
   private static String getAssociation(Field field) {
       StringBuilder association = new StringBuilder();
       //反射获取类名 和 类的包名
       String classPath = field.getType().getName();
       String className = field.getName();
       association.append("<association property=\"").append(className).append("\" ofType=\"").append(classPath).append("\">\n");
       association.append(pojoCore(field.getType()));
       iteration(field.getType(), association);
       association.append("</association>\n");
       return association.toString();
   }

    /**
     * 处理集合类型属性
     * @param field
     * @return
     */
    private static String getCollection(Field field) {
        StringBuilder collection = new StringBuilder();
        //反射获取类名 和 类的包名
        Class<?> genericType = getGenericType(field);
        String classPath = genericType.getName();
        String objectName = field.getName();
        collection.append("<collection property=\"").append(objectName).append("\" ofType=\"").append(classPath).append("\">\n");
        collection.append(pojoCore(genericType));
        iteration(genericType, collection);
        collection.append("</collection>\n");
        return collection.toString();
    }

    /**
     * 获取集合类型的泛型参数类型
     * @param field
     * @return
     */
    public static Class<?> getGenericType(Field field) {
        if (field.getType().isAssignableFrom(List.class)) {
            Type genericType = field.getGenericType();
            if (genericType instanceof ParameterizedType parameterizedType) {
                Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
                if (actualTypeArguments.length > 0) {
                    return (Class<?>) actualTypeArguments[0];
                }
            }
        }
        return null;
    }

    /**
     * 判断是否有对象类型嵌套属性
     * @param pojoClass
     * @return
     */
    private static List<Field> getChildPojo(Class<?> pojoClass){
        List<Field> result = new ArrayList<>();
        //判断是否有非基本对象类型
        Field[] fields = pojoClass.getDeclaredFields();
        for (Field field : fields) {
            if (isObjectType(field)) {
                result.add(field);
            }
        }
        return result;
    }

    /**
     * 判断是否有集合类型嵌套属性
     * @param pojoClass
     * @return
     */
    private static List<Field> getChildCollection(Class<?> pojoClass){
        List<Field> result = new ArrayList<>();
        //判断是否有非基本对象类型
        Field[] fields = pojoClass.getDeclaredFields();
        for (Field field : fields) {
            if (isCollectionType(field)) {
                result.add(field);
            }
        }
        return result;
    }

    /**
     * 驼峰命名转换为下划线命名
     * @param name 驼峰命名的字符串
     * @return
     */
   private static String camelCaseCast(String name) {
       StringBuilder result = new StringBuilder();
       if (name != null && !name.isEmpty()) {
           char[] charArray = name.toCharArray();
           result.append(charArray[0]);
           for (int i = 1; i < charArray.length; i++) {
               if (Character.isUpperCase(charArray[i])) {
                   result.append("_");
                   result.append(Character.toLowerCase(charArray[i]));
               }else {
                   result.append(charArray[i]);
               }
           }
       }
       return result.toString();
   }

    /**
     * 判断是否为基本数据类型
     * @param field
     * @return
     */
    private static boolean isCommonType(Field field){
        Class<?> type = field.getType();
        if (type.isPrimitive()) {
            return true;
        }
        return type == Integer.class || type == String.class || type == LocalDateTime.class || type == Date.class ||
                type == Boolean.class || type == Character.class || type == Byte.class || type == Short.class ||
                type == Long.class || type == Float.class || type == Double.class;
    }

    /**
     * 判断是否为对象类型
     * @param field
     * @return
     */
    private static boolean isObjectType(Field field){
        return !isCommonType(field) && !field.getType().isAssignableFrom(List.class);
    }

    /**
     * 判断是否为集合类型
     * @param field
     * @return
     */
    private static boolean isCollectionType(Field field){
        return field.getType().isAssignableFrom(List.class);
    }

    public static void main(String[] args) throws NoSuchFieldException {
//        System.out.println(pojoToResultMap(User.class ));
//        System.out.println(pojoCore(User.class));
//        System.out.println(getChildPojo(EClass.class));
//        System.out.println(getChildCollection(EClass.class));
        System.out.println(pojoToResultMap(EClass.class));
//        Friends friends = new Friends();
//        System.out.println(isCommonType(friends.getClass().getDeclaredField("age")));
    }
}
